Completed
Push — master ( eae854...eca82d )
by Rafael S.
124:29 queued 122:28
created

T_CONST ➔ bitdepth   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
nc 24
nop 4
dl 0
loc 1
rs 8.6666
c 1
b 0
f 0
1
/*
2
 * bitdepth: Change the resolution of samples to and from any bit depth.
3
 * https://github.com/rochars/bitdepth
4
 *
5
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining
8
 * a copy of this software and associated documentation files (the
9
 * "Software"), to deal in the Software without restriction, including
10
 * without limitation the rights to use, copy, modify, merge, publish,
11
 * distribute, sublicense, and/or sell copies of the Software, and to
12
 * permit persons to whom the Software is furnished to do so, subject to
13
 * the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be
16
 * included in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 */
27
28
/**
29
 * @fileoverview The bitdepth() function and private helper functions.
30
 */
31
32
/** @module bitdepth */
33
34
/** @private */
35
const f64f32_ = new Float32Array(1);
36
37
/**
38
 * Change the bit depth of samples. The input array.
39
 * @param {!TypedArray} input The samples.
40
 * @param {string} original The original bit depth of the data.
41
 *      One of "8" ... "53", "32f", "64"
42
 * @param {string} target The desired bit depth for the data.
43
 *      One of "8" ... "53", "32f", "64"
44
 * @param {!TypedArray} output The output array.
45
 */
46
export default function bitDepth(input, original, target, output) {
47
  validateBitDepth_(original);
48
  validateBitDepth_(target);
49
  /** @type {!Function} */
50
  let toFunction = getBitDepthFunction_(original, target);
51
  /** @type {!Object<string, number>} */
52
  let options = {
53
    oldMin: Math.pow(2, parseInt(original, 10)) / 2,
54
    newMin: Math.pow(2, parseInt(target, 10)) / 2,
55
    oldMax: (Math.pow(2, parseInt(original, 10)) / 2) - 1,
56
    newMax: (Math.pow(2, parseInt(target, 10)) / 2) - 1,
57
  };
58
  /** @type {number} */
59
  const len = input.length;
60
  // sign the samples if original is 8-bit
61
  if (original == "8") {
62
    for (let i=0; i<len; i++) {
63
      output[i] = input[i] -= 128;
64
    }
65
  }
66
  // change the resolution of the samples
67
  for (let i=0; i<len; i++) {        
68
    output[i] = toFunction(input[i], options);
69
  }
70
  // unsign the samples if target is 8-bit
71
  if (target == "8") {
72
    for (let i=0; i<len; i++) {
73
      output[i] = output[i] += 128;
74
    }
75
  }
76
}
77
78
/**
79
 * Change the bit depth from int to int.
80
 * @param {number} sample The sample.
81
 * @param {!Object<string, number>} args Data about the original and target bit depths.
82
 * @return {number}
83
 * @private
84
 */
85
function intToInt_(sample, args) {
86
  if (sample > 0) {
87
    sample = parseInt((sample / args.oldMax) * args.newMax, 10);
88
  } else {
89
    sample = parseInt((sample / args.oldMin) * args.newMin, 10);
90
  }
91
  return sample;
92
}
93
94
/**
95
 * Change the bit depth from float to int.
96
 * @param {number} sample The sample.
97
 * @param {!Object<string, number>} args Data about the original and target bit depths.
98
 * @return {number}
99
 * @private
100
 */
101
function floatToInt_(sample, args) {
102
  return parseInt(
103
    sample > 0 ? sample * args.newMax : sample * args.newMin, 10);
104
}
105
106
/**
107
 * Change the bit depth from int to float.
108
 * @param {number} sample The sample.
109
 * @param {!Object<string, number>} args Data about the original and target bit depths.
110
 * @return {number}
111
 * @private
112
 */
113
function intToFloat_(sample, args) {
114
  return sample > 0 ? sample / args.oldMax : sample / args.oldMin;
115
}
116
117
/**
118
 * Change the bit depth from float to float.
119
 * @param {number} sample The sample.
120
 * @return {number}
121
 * @private
122
 */
123
function floatToFloat_(sample) {
124
  f64f32_[0] = sample;
125
  return f64f32_[0];
126
}
127
128
/**
129
 * Return the function to change the bit depth of a sample.
130
 * @param {string} original The original bit depth of the data.
131
 *      One of "8" ... "53", "32f", "64"
132
 * @param {string} target The new bit depth of the data.
133
 *      One of "8" ... "53", "32f", "64"
134
 * @return {!Function}
135
 * @private
136
 */
137
function getBitDepthFunction_(original, target) {
138
  /** @type {!Function} */
139
  let func = function(x) {return x;};
140
  if (original != target) {
141
    if (["32f", "64"].includes(original)) {
142
      if (["32f", "64"].includes(target)) {
143
        func = floatToFloat_;
144
      } else {
145
        func = floatToInt_;
146
      }
147
    } else {
148
      if (["32f", "64"].includes(target)) {
149
        func = intToFloat_;
150
      } else {
151
        func = intToInt_;
152
      }
153
    }
154
  }
155
  return func;
156
}
157
158
/**
159
 * Validate the bit depth.
160
 * @param {string} bitDepth The original bit depth.
161
 *     Should be one of "8" ... "53", "32f" or "64".
162
 * @throws {Error} If any argument does not meet the criteria.
163
 * @private
164
 */
165
function validateBitDepth_(bitDepth) {
166
  if ((bitDepth != "32f" && bitDepth != "64") &&
167
      (parseInt(bitDepth, 10) < "8" || parseInt(bitDepth, 10) > "53")) {
168
    throw new Error("Invalid bit depth.");
169
  }
170
}
171